package com.superbytecode.cloud.common.model;

import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * All rights Reserved, Designed By www.super-master.cn
 *
 * @ProjectName: sanskrit
 * @Package: com.superbytecode.sanskrit.core.dict
 * @ClassName: IDict
 * @Description: [字典接口]
 * <p>
 * 自定义的字典枚举类实现本接口后可省略属性code和text，以及对应的get方法
 * <br>
 * 在构造方法中只需调用init方法即可初始化
 * </p>
 * @Author: [Lance Ting]
 * @Date: 2024/8/14 17:58
 * @Version: V1.0
 * @Copyright: 2024 www.super-master.cn Inc. All rights reserved.
 * TODO: 注意,本文件Lance Ting所作,如果转载或使用请标明具体出处!
 **/
public interface IDict<T> {
    default void initDict(T code, String message) {
        DictPool.putDict(this, code, message);
    }

    /**
     * 获取字典编码
     *
     * @return 编码
     */
    default T obtainCode() {
        return DictPool.getDict(this).getDictCode();
    }

    /**
     * 获取字典描述
     *
     * @return 文本
     */
    default String obtainValue() {
        return DictPool.getDict(this).getDictValue();
    }
    //---------------------------------------------------------------------------------------------------------------

    /**
     * 通过code获取字典枚举描述
     *
     * @param clazz 枚举class
     * @param code  编码code
     * @param <T>   枚举类型
     * @return 字典code类型
     */
    static <T> String obtainValueByCode(Class<? extends IDict<T>> clazz, T code) {
        return Stream.of(clazz.getEnumConstants())//
                .filter((IDict<T> e) -> Objects.equals(e.obtainCode(), code))//
                .map(IDict::obtainValue)//
                .findAny().orElse(null);
    }

    /**
     * 通过code获取字典枚举实例
     *
     * @param clazz 枚举class
     * @param code  code
     * @param <T>   字典code类型
     * @param <R>   枚举类型
     * @return 字典枚举实例
     */
    @SuppressWarnings("unchecked")
    static <T, R extends IDict<T>> R obtainByCode(Class<? extends IDict<T>> clazz, T code) {
        return Stream.of(clazz.getEnumConstants())//
                .filter((IDict<T> e) -> Objects.equals(e.obtainCode(), code))//
                .map(v -> (R) v)//
                .findAny()//
                .orElse(null);
    }

    /**
     * 通过text获取code
     *
     * @param clazz 枚举class
     * @param desc  描述
     * @param <T>   枚举类型
     * @return code
     */
    static <T> T obtainCodeByValue(Class<? extends IDict<T>> clazz, String desc) {
        return Stream.of(clazz.getEnumConstants())//
                .filter((IDict<T> e) -> Objects.equals(e.obtainValue(), desc))//
                .map(IDict::obtainCode)//
                .findAny().orElse(null);
    }

    /**
     * 获取给定的字典枚举项（常用下拉框数据请求）
     *
     * @param enums 可指定需要哪些项
     * @param <T>   枚举类型
     * @param <E>   字典类型
     * @return list
     */
    @SafeVarargs
    static <T, E extends IDict<T>> List<IDict<T>> getDicts(E... enums) {
        return Stream.of(enums).map(DictPool::getDict).collect(Collectors.toList());
    }

    /**
     * 获取(指定的枚举之外)所有字典枚举项，除开指定的枚举
     *
     * @param exclude 指定排除的枚举列表
     * @return List
     */
    @SafeVarargs
    @SuppressWarnings("unchecked")
    static <T, E extends IDict<T>> List<IDict<T>> getExclude(E... exclude) {
        Class<IDict<T>> clazz = (Class<IDict<T>>) exclude.getClass().getComponentType();
        IDict<T>[] allEnum = clazz.getEnumConstants();
        List<IDict<T>> excludeList = Arrays.asList(exclude);
        return Stream.of(allEnum).filter(e -> !excludeList.contains(e))//
                .map(DictPool::getDict).collect(Collectors.toList());
    }

    /**
     * 获取所有字典枚举项（常用下拉框数据请求）
     * 枚举值上标记@Deprecated的不会返回
     *
     * @param clazz 字典枚举类
     * @return List
     */
    static <T> List<IDict<T>> getAll(Class<? extends IDict<T>> clazz) {
        Map<String, Field> enumFieldCache = Arrays.stream(clazz.getDeclaredFields())//
                .filter(Field::isEnumConstant)//
                .collect(Collectors.toMap(Field::getName, Function.identity()));
        IDict<T>[] allEnum = clazz.getEnumConstants();
        return Stream.of(allEnum)
                // 排除标记@Deprecated的类
                .filter(e -> !enumFieldCache.get(((Enum<?>) e).name()).isAnnotationPresent(Deprecated.class))//
                .map(DictPool::getDict).collect(Collectors.toList());
    }


    //---------------------------------------------------------------------------------------------------------------
    @SuppressWarnings("all")
    class DictPool {
        private static final Map<IDict, DictBean> DICT_MAP = new ConcurrentHashMap<>();
        private static final Map<String, Class<? extends IDict>> DICT_NAME_CLASS_MAP = new ConcurrentHashMap<>();

        static <T> void putDict(IDict<T> dict, T code, String desc) {
            DICT_NAME_CLASS_MAP.put(dict.getClass().getName(), dict.getClass());
            DICT_MAP.put(dict, new DictBean<>(code, desc));
        }

        public static List<IDict<Object>> getDict(String dictName) {
            Class<? extends IDict> clazz = DICT_NAME_CLASS_MAP.get(dictName);
            return IDict.getAll((Class<? extends IDict<Object>>) clazz);
        }

        static <K extends IDict<T>, T> DictBean<T> getDict(K dict) {
            return DICT_MAP.get(dict);
        }
    }
}